// =============================================
// FD Domain Warp Generative (EFFECT)
// Made by Ubik and Claude 2026
// =============================================
// Self-generating domain warp feedback.
// No video input needed - generates its own
// geometric ring/spiral patterns internally
// and feeds them through its own warp loop.
//
// Patching:
//   [Actor A: out] -> [Actor B: video in 1]
//   [Actor B: out] -> [Actor A: video in 1]  <- feedback delay
//   [Actor A: out] -> [Projector]
// =============================================

// ISADORA_PLUGIN_DESC("Domain Warp Generative - self-generating domain warp feedback. No video input needed. Connect Actor B feedback to in 1.")

// ISADORA_FLOAT_PARAM(gen_scale, gnsc, 0.1, 8.0, 2.5, "Scale of the geometric pattern. Low = large rings, high = dense fine rings.")
// ISADORA_FLOAT_PARAM(gen_speed, gnsp, 0.0, 4.0, 0.7, "How fast the rings pulse and rotate.")
// ISADORA_FLOAT_PARAM(warp_strength, wstr, 0.0, 0.25, 0.055, "How strongly the feedback is deformed by the wave field each frame.")
// ISADORA_FLOAT_PARAM(warp_speed, wspd, 0.0, 3.0, 0.5, "How fast the wave field moves. Low = slow dreamy morph, high = fast turbulence.")
// ISADORA_FLOAT_PARAM(decay, deca, 0.0, 0.99, 0.9, "How long feedback structures persist. High = deep persistence and build-up.")

uniform float gen_scale;
uniform float gen_speed;
uniform float warp_strength;
uniform float warp_speed;
uniform float decay;
uniform float iTime;
uniform vec3  iResolution;
uniform sampler2D tex0;

vec3 rgb2hsv(vec3 c)
{
    float cmax  = max(c.r, max(c.g, c.b));
    float cmin  = min(c.r, min(c.g, c.b));
    float delta = cmax - cmin;
    float h = 0.0;
    if (delta > 0.0001)
    {
        if      (cmax == c.r) h = mod((c.g - c.b) / delta, 6.0);
        else if (cmax == c.g) h = (c.b - c.r) / delta + 2.0;
        else                  h = (c.r - c.g) / delta + 4.0;
        h /= 6.0;
        if (h < 0.0) h += 1.0;
    }
    float s = (cmax < 0.0001) ? 0.0 : delta / cmax;
    return vec3(h, s, cmax);
}

vec3 hsv2rgb(vec3 c)
{
    float h = c.x * 6.0;
    float s = c.y;
    float v = c.z;
    float i = floor(h);
    float f = h - i;
    float p = v * (1.0 - s);
    float q = v * (1.0 - s * f);
    float t = v * (1.0 - s * (1.0 - f));
    if      (i < 1.0) return vec3(v, t, p);
    else if (i < 2.0) return vec3(q, v, p);
    else if (i < 3.0) return vec3(p, v, t);
    else if (i < 4.0) return vec3(p, q, v);
    else if (i < 5.0) return vec3(t, p, v);
    else               return vec3(v, p, q);
}

void main()
{
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float t = iTime * gen_speed;
    float aspect = iResolution.x / iResolution.y;

    // --- Generative geometric input ---
    // Centred coordinate system with aspect correction
    vec2 centered = (uv - 0.5) * vec2(aspect, 1.0);

    float r = length(centered);
    float angle = atan(centered.y, centered.x);
    float rotation = t * 0.13;

    // Primary rings - pulsing concentric circles
    float rings = sin(r * gen_scale * 6.2832 - t * 2.0) * 0.5 + 0.5;

    // Secondary rings - slightly faster, different scale
    float rings2 = sin(r * gen_scale * 3.7 + t * 1.3 + 1.0) * 0.5 + 0.5;

    // Angular modulation - turns rings into spirals/rosettes
    float angular = sin(angle * 6.0 + rotation + r * gen_scale * 2.0) * 0.5 + 0.5;

    // Off-centre secondary source - creates interference patterns
    vec2 offcenter = vec2(cos(iTime * 0.31) * 0.25, sin(iTime * 0.23) * 0.25);
    float r2 = length(centered - offcenter);
    float rings3 = sin(r2 * gen_scale * 5.1 - t * 1.7) * 0.5 + 0.5;

    // Combine all layers
    float pattern = rings * 0.4 + rings2 * 0.3 + angular * 0.15 + rings3 * 0.15;

    // Colour: hue driven by radial position and slow time drift - always colourful
    float hueBase = mod(r * gen_scale * 0.3 + iTime * 0.05, 1.0);
    vec3 genColor = hsv2rgb(vec3(hueBase, 0.85, pattern));

    // --- Domain warp on previous frame (feedback via tex0) ---
    float wt = iTime * warp_speed;
    float wx = sin(uv.y * 3.9 + wt) * cos(uv.x * 4.3 - wt * 0.7)
             + sin(uv.y * 7.1 - wt * 0.5 + 1.4) * 0.4;
    float wy = cos(uv.x * 4.1 + wt * 0.8) * sin(uv.y * 3.5 + wt * 1.2)
             + cos(uv.x * 6.3 - wt * 0.6 + 0.9) * 0.4;

    vec2 warpedUV = clamp(uv + vec2(wx, wy) * warp_strength, 0.0, 1.0);

    // Sample warped feedback frame
    vec4 prevFrame = texture2D(tex0, warpedUV);
    vec3 feedback  = prevFrame.rgb * decay;

    // Add generative input into feedback
    vec3 result = clamp(feedback + genColor * (1.0 - decay) * 1.5, 0.0, 1.0);

    gl_FragColor = vec4(result, 1.0);
}
